from flask import Flask, request, jsonify
import mysql.connector
from flask_cors import CORS
import bcrypt
# 导入库


# 创建一个 Flask 应用实例，并为该应用启用跨域资源共享（CORS
app = Flask(__name__)
CORS(app)

# 全局数据库连接和游标
cnx = None
cursor = None

# 连接数据库
# 定义一个函数，用于连接 MySQL 数据库
def connect_to_mysql():
    # 函数内部使用 global 关键字声明变量 cnx 和 cursor 时，它表示你在函数内部使用的 cnx 和 cursor 变量是全局变量，而不是函数内部的局部变量
    global cnx,cursor
    try:
        # 创建连接对象cnx在代码块结束时自动关闭连接
        cnx = mysql.connector.connect(
            # 数据库服务器的主机地址，这里是本地主机
            host="localhost",
            # 数据库服务器的端口号，根据实际情况修改
            port=3434,
            # 数据库用户名
            user="root",
            # 密码
            password="123456",
            # 要连接的数据库名称
            database="pythonsql"
        )
            # 检查是否成功连接到数据库
        if cnx.is_connected():
                print("成功连接数据库")
                # 创建游标对象,用于执行 SQL 命令
                cursor = cnx.cursor()
        else:
                print("数据库连接失败")


                # 执行 SQL 查询,查询表中所有数据
                # cursor.execute("SELECT * FROM demo")
                # print('查询成功')
                # 获取查询结果，返回一个元组列表，其中每个元组代表一行数据
                # result = cursor.fetchall()
                # 遍历查询结果并打印每一行
                # for row in result:
                #     print(row)
                # 关闭游标，释放资源
                # cursor.close()

    # 如果出现错误时打印异常
    except mysql.connector.Error as err:
        print(f"Error: {err}")



# 定义一个名为 register_user 的函数，该函数接收两个参数：username 和 password，用于注册新用户
def register_user(username, password):
    global cnx,cursor
    # 调用 connect_to_mysql 函数，尝试连接到 MySQL 数据库，并将返回的数据库连接对象 cnx 和游标对象 cursor 存储在变量中
    # cnx, cursor = connect_to_mysql()
    # 检查 cnx 和 cursor 是否都不为 None，如果都不为 None，表示成功建立数据库连接并获取到了游标，继续执行后续操作；否则，可能是连接数据库时出现了问题，不会执行后续操作
    if cnx and cursor:
        # 开始一个 try 块，用于执行可能会引发异常的代码，主要是数据库操作
        try:
            # 检查连接是否仍然有效
            if cnx.is_connected():
                # 定义一个 SQL 插入语句 insert_query，使用参数化查询（%s 作为占位符），避免 SQL 注入。该语句将向 users 表中插入一条新的用户记录，包含 username 和 password 字段
                insert_query = "INSERT INTO users (username, password) VALUES (%s, %s)"
                # 对密码进行哈希处理，此处只是简单地将密码赋值给 hashed_password，在实际应用中应使用更安全的哈希算法，如 bcrypt 或 argon2
                hashed_password = password
                # 将 username 和 hashed_password 作为元组存储在 data 变量中，用于后续作为参数传递给 execute 方法
                data = (username, hashed_password)
                # 使用游标对象 cursor 执行 SQL 插入语句 insert_query，将 data 作为参数传递给 execute 方法，插入新用户信息
                cursor.execute(insert_query, data)
                # 提交事务，将插入操作持久化到数据库中
                cnx.commit()
                return jsonify({"message": "用户注册成功"})
                    # print("用户注册成功")
            else:
                return jsonify({"error":"数据库连接已断开"}),500        
        # 如果在 try 块中出现 mysql.connector.Error 异常，将异常信息存储在 err 变量中
        except mysql.connector.Error as err:
            return jsonify({"error": f"注册用户时出错: {err}"}), 500
            # print(f"注册用户时出错: {err}")
        # finally 块确保无论是否发生异常，以下代码都会执行
        # finally:
            # 关闭游标对象，释放资源
            # cursor.close()
            # 关闭数据库连接对象，释放资源
            # cnx.close()
    else:
        return jsonify({"error":"数据库连接失败"}),500        


# 登录验证
# 定义一个名为 login_user 的函数，该函数接收两个参数：username 和 password，用于用户登录验证
def login_user(username, password):
    global cnx,cursor
    # 调用 connect_to_mysql 函数，尝试连接到 MySQL 数据库，并将返回的数据库连接对象 cnx 和游标对象 cursor 存储在变量中
    # cnx, cursor = connect_to_mysql()
    # 检查 cnx 和 cursor 是否都不为 None，以确保成功建立数据库连接和获取到游标，以便后续操作
    if cnx and cursor:
        # 开始一个 try 块，执行可能引发异常的数据库操作
        try:
            # 定义一个 SQL 查询语句 select_query，使用参数化查询，根据用户名查找用户信息
            select_query = "SELECT * FROM users WHERE username = %s"
            # 将 username 和 password 存储在 data 元组中，用于传递给 execute 方法
            data = (username, password)
            # 使用游标对象 cursor 执行 SQL 查询语句 select_query，并将 data 作为参数传递给 execute 方法
            cursor.execute(select_query, data)
            # 使用 fetchone 方法从结果集中获取一条记录，如果有结果表示找到了匹配的用户，存储在 user 变量中；如果没有结果，user 为 None
            user = cursor.fetchone()
            # 检查是否找到了用户记录。
            if user:
                # 密码字段位置（从0开始索引
                stored_password = user[2]
                # 使用 bcrypt 库的 checkpw 方法检查用户输入的密码是否与存储在数据库中的密码匹配。
                # password.encode('utf-8')：将用户输入的密码编码为字节串。
                # stored_password.encode('utf-8')：将存储在数据库中的密码编码为字节串。
                if bcrypt.checkpw(password.encode('utf-8'), stored_password.encode('utf-8')):
                    return jsonify({"message": "登录成功"})
                else:
                    return jsonify({"error": "用户名或密码错误"}), 401
                # print("登录成功")
            # 如果 user 为 None，表示未找到匹配的用户
            else:
                return jsonify({"error": "用户名或密码错误"}), 401
                # print("用户名或密码错误")
        # 如果在 try 块中出现 mysql.connector.Error 异常，将异常信息存储在 err 变量中
        except mysql.connector.Error as err:
            return jsonify({"error": f"登录时出错: {err}"}), 500
            # print(f"登录时出错: {err}")
        # finally 块确保无论是否发生异常，以下代码都会执行
        # finally:
            # 关闭游标对象，释放资源 
            # cursor.close()
            # 关闭数据库连接对象，释放资源
            # cnx.close()
    else:
        return jsonify({"error":"数据库连接失败"}),500        


# 使用装饰器定义一个路由 /register，该路由只接受 POST 方法的请求
@app.route('/register', methods=['POST'])
# 定义处理 /register 路由的函数
def register():
    # 从请求中解析 JSON 数据，并将其存储在 data 变量中
    data = request.get_json()
    # 从 data 中提取 username 和 password 字段的值
    username = data.get('username')
    password = data.get('password')
    # 检查 username 和 password 是否都不为 None 或空字符串
    if username and password:
        # 如果用户名和密码都存在，调用 register_user 函数进行用户注册，并将其结果作为响应返回
        return register_user(username, password)
    else:
        # 如果用户名或密码不存在，返回一个包含错误信息的 JSON 响应，状态码为 400（Bad Request）
        return jsonify({"error": "请提供用户名和密码"}), 400


# 类似 register 路由，定义 /login 路由，只接受 POST 方法的请求，并定义处理该路由的函数
@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    if username and password:
        # 调用 login_user 函数进行用户登录验证，并将其结果作为响应返回
        return login_user(username, password)
    else:
        return jsonify({"error": "请提供用户名和密码"}), 400


# 测试
# 定义一个名为 main 的函数，作为程序的入口点
# def main():
    # 调用 register_user 函数，传入用户名 test_user 和密码 test_password 进行用户注册测试
    # register_user("test_user", "test_password")
    # 调用 login_user 函数，传入用户名 test_user 和密码 test_password 进行用户登录测试
    # login_user("test_user", "test_password")



if __name__ == '__main__':
    connect_to_mysql()
    app.run(debug=True)
    